#ifndef AIRCACHE_APPLICATION_H
#define AIRCACHE_APPLICATION_H


#include "ns3/address.h"
#include "ns3/application.h"
#include "ns3/event-id.h"
#include "ns3/ptr.h"
#include "ns3/socket.h"
#include "ns3/inet-socket-address.h"
#include "ns3/data-rate.h"
#include "ns3/traced-callback.h"
#include "ns3/nstime.h"
#include "basic_channel.h"
#include "ac_header.h"
#include <string>
#include <vector>
#include "ns3/log.h"
#include "ns3/address.h"
#include "ns3/inet6-socket-address.h"
#include "ns3/node.h"
#include "ns3/data-rate.h"
#include "ns3/random-variable-stream.h"
#include "ns3/simulator.h"
#include "ns3/packet.h"
#include "ns3/uinteger.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/udp-socket-factory.h"
#include "ns3/string.h"
#include "ns3/pointer.h"
#include "ns3/random-variable.h"
#include "ns3/ipv4.h"
#include "ns3/packet-socket-address.h"
#include <iostream>
#include "ac_file.h"
#include "fileInfo.h"
#include "OutGoingPackets.h"
#include "InComingPackets.h"
#include "ns3/energy-module.h"
#include "ns3/integer.h"
#include <fstream>
#include <iostream>


namespace ns3 {

class Address;
class RandomVariableStream;
class Socket;

class AirCacheApplication : public Application 
{
public:



  static TypeId GetTypeId (void);

  AirCacheApplication ();

  virtual ~AirCacheApplication();

  Ptr<Socket> GetSocket (void) const;
  

  void init();
  void handleFile(ACFile);
  bool searchFile(ACFile);
  Ptr<Packet> createPacket(uint32_t,uint32_t,std::vector<BasicChannel>);
  void handlePacket(Ptr<Packet>);
  void handleFrameInformation(std::vector<BasicChannel>,uint64_t,uint32_t);
  bool searchPublicTableFileInfo(std::string);
  void insertNodeEntryInPublicTableFileInfo(std::string,uint32_t,uint32_t);
  void updatePublicTable(std::string,uint32_t,uint32_t);
  void printPublicTable();
  bool maxValueReplicaData(uint32_t);
  void deleteFileAndTraces(std::string);
    std::vector<BasicChannel> prepareOutgoingFI(std::vector<int>,std::vector<BasicChannel>);
    void updateListenedNodesLists(uint32_t);
    void updateNodeLinkedMap(uint32_t,uint32_t);
    bool mostLinkedNode();
    void handlePublicTable(std::vector<FileInfo>,uint32_t);
    int retIndexPubTableGivenFilename(std::string);
    uint16_t calcListenedNodes(std::vector<BasicChannel>);
    uint32_t bytesSentInBasicChannel();
    uint32_t calculateNumbOfSlotsToReserve(uint32_t);
    void reserveAllFreeSlots();
    void scheduleFragmentToSend(Time);
    void sendFragment(uint32_t);
    bool searchInListenedNodes(std::vector<int>,uint32_t);
    void slotReservation(uint32_t,uint32_t);
    int searchIdPacketIn_Incoming(uint32_t);
    Ptr<Packet> retrievePacket(uint32_t);
    void doubleFrameInformation();
    bool filePresentInListenedNodes(std::string );
    std::string getfileNameInPacketType4(Ptr<Packet>);
    bool searchFileNameInOutGoingPackets(std::string);
    void halveFrameInformation();
    uint32_t numbOfEffectiveNodes(std::vector<BasicChannel>);
    void printListofFileNames();
    bool nodeInAreaOfInterest();
    void lookingMode();
    bool checkIfnodeIsFarFromAreaOfInterest();
    void closeSockets();
    void CreateSockets();
    void eraseAllDataStructures();

  

  Time frameInfBeginTime;
  uint32_t frameInformationLength;
  Time basicChannelLength;
  int basicChannelPosition;
  bool initialized;
  bool sending;
  InetSocketAddress local;
  std::vector<BasicChannel>  frameInformation; // the frame information array
  std::vector<ACFile>  fileList; //the vector contain the files owned by the node
  std::vector<std::string> ListOfFileNames;
  std::vector<FileInfo> publicTable;
  std::map<uint32_t,uint32_t> mapListenedNodes;  // mapPublicTableSize
  std::vector<int> listenedNodesSize;
  std::vector<int> listenedNodes;
  std::vector<int> memolistenedNodes;
  std::vector<BasicChannel> memoFI;
    uint32_t memoSlotsToReserve;
  std::vector<OutGoingPackets> outGoingPacketsList;
  std::vector<Ptr<Packet> > outPacketsList;
  std::vector<InComingPackets> inComingPackets;
    Ptr<BasicEnergySource> basicSourcePtr;
    std::string aoiFileName;

    /*Area of Interest Coordinates retrieved from the file*/
    uint32_t aoi_x;
    uint32_t aoi_y;
    uint32_t dist;
       
    
    int batteryPercentage;
  int node_id;
  std::string fileName;
  uint32_t fileSize;
  double s_upper;
  double s_lower;
   TracedValue<bool> ownFile;

    uint32_t lowerFILength;
  uint32_t  outFILength; // the frame information used to broadcast

    uint32_t slotsToReserve;
    
    


protected:
  virtual void DoDispose (void);
private:
  // inherited from Application base class.
  virtual void StartApplication (void);    // Called at time specified by Start
  virtual void StopApplication (void);     // Called at time specified by Stop

  //helpers
  void CancelSendEvents ();

  void Construct (Ptr<Node> n,
                  const Address &remote,
                  std::string tid,
                  const RandomVariable& ontime,
                  const RandomVariable& offtime,
                  uint32_t size);


  void mergeFI(std::vector<BasicChannel>,uint32_t);
  void joinAirCache();

  // Event handlers
  void StartSending ();
  void StopSending ();
  void SendPacket ();
    
  void StopListening();  // stop the listen mode
  void HandleRead (Ptr<Socket>);

  Ptr<Socket>     m_socket;       // Associated socket source socket
  Ptr<Socket>     s_socket;       // Associated socket sink socket
  uint16_t        m_port;
  bool            m_connected;    // True if connected
  DataRate        m_cbrRate;      // Rate that data is generated
  uint32_t        m_pktSize;      // Size of packets
  uint32_t        m_residualBits; // Number of generated, but not sent, bits
  Time            m_lastStartSendTime; // Time last packet sent
  uint32_t        m_totBytes;     // Total bytes sent so far
  EventId         m_startStopSendEvent;     // Event id for next start or stop event
  EventId         m_sendEvent;    // Eventid of pending "send packet" event
  EventId         m_stopSending;
  EventId         m_looking_mode1;
  EventId         m_looking_mode2;
  EventId         m_looking_mode3;
  EventId         m_joining_ac1;
  EventId         m_joining_ac2;

  TypeId          m_tid;

  


private:
  void ScheduleNextTx ();
  void ScheduleStartTransmissionEvent ();
  void ScheduleStopTransmissionEvent ();
  void ConnectionSucceeded (Ptr<Socket> socket);
  void ConnectionFailed (Ptr<Socket> socket);
  void frameInfNodeChoose();

//NEW
 int  basicChannelPos();
 void selfUpdateFI();
  
 void stampaFI(std::vector<BasicChannel>);

  void startTransmission(); // Comincia a trasmettere (frame information + altro)
  void stopTransmission();  //stop the transmission mode
  
};

} // namespace ns3

#endif /* AirCache_APPLICATION_H */
